package com.ideaaedi.springcloud.jd.user.exception;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.ideaaedi.springcloud.jd.commonds.entity.CodeMsgProvider;
import com.ideaaedi.springcloud.jd.commonds.entity.Result;
import lombok.Getter;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer;
import org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Serializer;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * jd oauth2
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2022/9/3 23:27:45
 */
@JsonSerialize(using = JdOAuth2Exception.JdOAuth2ExceptionJackson2Serializer.class)
@JsonDeserialize(using = JdOAuth2Exception.JdOAuth2ExceptionJackson2Deserializer.class)
public class JdOAuth2Exception extends OAuth2Exception {
    
    @Getter
    private final Result<?> result;
    
    public JdOAuth2Exception(CodeMsgProvider codeMsgProvider) {
        super(codeMsgProvider.message());
        this.result = Result.failure(codeMsgProvider);
    }
    
    public JdOAuth2Exception(String msg, CodeMsgProvider codeMsgProvider) {
        super(msg);
        this.result = Result.failure(codeMsgProvider);
    }
    
    public JdOAuth2Exception(Result<?> result) {
        super(JSON.toJSONString(result));
        this.result = result;
    }
    
    public JdOAuth2Exception(Result<?> result, String msg, Throwable t) {
        super(msg + "\t with result" + JSON.toJSONString(result), t);
        this.result = result;
    }
    
    public JdOAuth2Exception(Result<?> result, String msg) {
        super(msg + "\t with result" + JSON.toJSONString(result));
        this.result = result;
    }
    
    /**
     * 参考{@link OAuth2ExceptionJackson2Serializer}编写序列化逻辑即可
     */
    public static class JdOAuth2ExceptionJackson2Serializer extends StdSerializer<JdOAuth2Exception> {
    
        protected JdOAuth2ExceptionJackson2Serializer() {
            super(JdOAuth2Exception.class);
        }
    
        @Override
        public void serialize(JdOAuth2Exception value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            Result<?> result = value.getResult();
            jgen.writeStringField("code", result.getCode());
            jgen.writeStringField("msg", result.getMsg());
            jgen.writeStringField("traceId", result.getTraceId());
            jgen.writeObjectField("data",result.getData());
            jgen.writeEndObject();
        }
    }
    
    /**
     * 参考{@link OAuth2ExceptionJackson2Deserializer}编写反序列化逻辑即可
     */
    @SuppressWarnings("AlibabaClassNamingShouldBeCamel")
    public static class JdOAuth2ExceptionJackson2Deserializer extends StdDeserializer<JdOAuth2Exception>{
    
        protected JdOAuth2ExceptionJackson2Deserializer() {
            super(JdOAuth2Exception.class);
        }
    
        @Override
        public JdOAuth2Exception deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException {
            JsonToken t = jp.getCurrentToken();
            if (t == JsonToken.START_OBJECT) {
                t = jp.nextToken();
            }
            Map<String, Object> errorParams = new HashMap<String, Object>();
            for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
                // Must point to field name
                String fieldName = jp.getCurrentName();
                // And then the value...
                t = jp.nextToken();
                // Note: must handle null explicitly here; value deserializers won't
                Object value;
                if (t == JsonToken.VALUE_NULL) {
                    value = null;
                }
                // Some servers might send back complex content
                else if (t == JsonToken.START_ARRAY) {
                    value = jp.readValueAs(List.class);
                }
                else if (t == JsonToken.START_OBJECT) {
                    value = jp.readValueAs(Map.class);
                }
                else {
                    value = jp.getText();
                }
                errorParams.put(fieldName, value);
            }
    
            // 将json信息反序列化为JdOAuth2Exception
            Result<Object> result = new Result<>();
            result.setCode(errorParams.get("code") == null ? null : errorParams.get("code").toString());
            result.setMsg(errorParams.get("msg") == null ? null : errorParams.get("msg").toString());
            result.setTraceId(errorParams.get("traceId") == null ? null : errorParams.get("traceId").toString());
            result.setData(errorParams.get("data"));
            return new JdOAuth2Exception(result);
        }
    }
}
